package org.ysling.litemall.core.tasks.config;
/**
 *  Copyright (c) [ysling] [927069313@qq.com]
 *  [litemall-plus] is licensed under Mulan PSL v2.
 *  You can use this software according to the terms and conditions of the Mulan PSL v2.
 *  You may obtain a copy of Mulan PSL v2 at:
 *              http://license.coscl.org.cn/MulanPSL2
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PSL v2 for more details.
 */
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.ysling.litemall.core.system.SystemConfig;
import org.ysling.litemall.core.tasks.impl.*;
import org.ysling.litemall.core.tasks.service.TaskService;
import org.ysling.litemall.core.tenant.handler.TenantContextHolder;
import org.ysling.litemall.db.domain.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.ysling.litemall.db.service.*;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

/**
 * 定时检查所有执行失败的任务
 * @author Ysling
 */
@Slf4j
@Component
public class TaskJob {



    @Autowired
    private TaskJobService taskJobService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private ITenantService tenantService;


    private ArrayList<String> getTenantIds(){
        List<LitemallTenant> tenantList = tenantService.list();
        ArrayList<String> idList = new ArrayList<>();
        for (LitemallTenant tenant :tenantList) {
            idList.add(tenant.getId());
        }
        idList.add(TenantContextHolder.getDefaultId());
        return idList;
    }



    /**
     * 自动确认收货延时队列检查
     * <p>
     * 定时时间是每天凌晨1点。
     *
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void checkOrderUnconfirmed() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-订单自动确认收货]");
            List<LitemallOrder> orderList = taskJobService.queryUnconfirmed();
            for (LitemallOrder order : orderList) {
                LocalDateTime ship = order.getShipTime();
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime expire = ship.plusDays(SystemConfig.getOrderUnconfirmed());
                if (expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new OrderUnconfirmedTask(order, 0));
                } else {
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-订单自动确认收货][超时时间=%s毫秒]", delay));
                    taskService.addTask(new OrderUnconfirmedTask(order, delay));
                }
            }

            log.info(String.format("租户[%s] ->系统定时任务 -> [结束检查-订单自动确认收货][检查结果={数量%s}]",tenantId, orderList.size()));
            TenantContextHolder.removeLocalTenantId();
        }
    }

    /**
     * 团购延时队列检查
     * <p>
     * 定时时间是每天凌晨2点。
     *
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void checkGrouponRuleExpired() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-团购规则过期]");
            List<LitemallGrouponRules> grouponRulesList = taskJobService.queryGrouponRulesExpired();
            for(LitemallGrouponRules grouponRules : grouponRulesList){
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime expire =  grouponRules.getExpireTime();
                if(expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new GrouponRuleExpiredTask(grouponRules, 0));
                }
                else{
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-团购规则过期][超时时间=%s毫秒]" , delay));
                    taskService.addTask(new GrouponRuleExpiredTask(grouponRules, delay));
                }
            }

            log.info(String.format("租户[%s] ->系统定时任务 -> [结束检查-团购规则过期][检查结果={数量%s}]",tenantId , grouponRulesList.size()));

            TenantContextHolder.removeLocalTenantId();
        }
    }

    /**
     * 订单超时支付延时队列检查
     * <p>
     * 定时时间是每天凌晨3点。
     */
    @Scheduled(cron = "0 0 3 * * ?")
    public void checkOrderUnpaid() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-订单支付超时]");
            List<LitemallOrder> orderList = taskJobService.queryUnpaid();
            for (LitemallOrder order : orderList) {
                LocalDateTime add = order.getAddTime();
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime expire = add.plusMinutes(SystemConfig.getOrderUnpaid());
                if (expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new OrderUnpaidTask(order, 0));
                } else {
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-订单支付超时][超时时间=%s毫秒]", delay));
                    taskService.addTask(new OrderUnpaidTask(order, delay));
                }
            }
            log.info(String.format("租户[%s] ->系统定时任务 -> [结束检查-订单支付超时][检查结果={数量%s}]",tenantId , orderList.size()));

            TenantContextHolder.removeLocalTenantId();
        }
    }

    /**
     * 可评价订单商品超期
     * <p>
     * 定时时间是每天凌晨4点。
     */
    @Scheduled(cron = "0 0 4 * * ?")
    public void checkOrderComment() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-订单评论超时]");
            //查询所有评论超时订单
            List<LitemallOrder> orderList = taskJobService.queryComment();
            for(LitemallOrder order : orderList){
                LocalDateTime add = order.getConfirmTime();
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime expire =  add.plusDays(SystemConfig.getOrderComment());
                if(expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new OrderCommentTask(order, 0));
                }
                else{
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-订单评论超时][超时时间=%s毫秒]" , delay));
                    taskService.addTask(new OrderCommentTask(order, delay));
                }
            }
            log.info(String.format("租户[%s] ->系统定时任务 -> [结束检查-订单评论超时][检查结果={数量%s}]" , tenantId, orderList.size()));

            TenantContextHolder.removeLocalTenantId();
        }
    }

    /**
     * 检查优惠券是否已经过期
     * <p>
     * 定时时间是每天凌晨5点。
     */
    @Scheduled(cron = "0 0 5 * * ?")
    public void checkCouponExpired() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-优惠券是否已经过期]");
            //查询所有已经过期优惠券
            List<LitemallCoupon> couponList = taskJobService.queryCouponExpired();
            for(LitemallCoupon coupon : couponList){
                LocalDateTime expire = coupon.getEndTime();
                LocalDateTime now = LocalDateTime.now();
                if(expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new CouponExpiredTask(coupon, 0));
                }
                else{
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-优惠券是否已经过期][超时时间=%s毫秒]" , delay));
                    taskService.addTask(new CouponExpiredTask(coupon, delay));
                }
            }
            log.info(String.format("租户[%s] ->系统定时任务 -> [结束检查-优惠券是否已经过期][检查结果={数量%s}]",tenantId , couponList.size()));

            TenantContextHolder.removeLocalTenantId();
        }
    }

    /**
     * 检查用户优惠券是否已经过期
     * <p>
     * 定时时间是每天凌晨6点。
     */
    @Scheduled(cron = "0 0 6 * * ?")
    public void checkCouponUserExpired() {
        for (String tenantId : getTenantIds()) {
            TenantContextHolder.setLocalTenantId(tenantId);
            log.info("系统定时任务 -> [开始检查-用户优惠券是否已经过期]");
            //查询所有已经过期优惠券
            List<LitemallCouponUser> couponList = taskJobService.queryCouponUserExpired();
            for(LitemallCouponUser couponUser : couponList){
                LocalDateTime expire = couponUser.getEndTime();
                LocalDateTime now = LocalDateTime.now();
                if(expire.isBefore(now)) {
                    // 已经过期，则加入延迟队列
                    taskService.addTask(new CouponUserExpiredTask(couponUser, 0));
                }
                else{
                    // 还没过期，则加入延迟队列
                    long delay = ChronoUnit.MILLIS.between(now, expire);
                    log.info(String.format("系统定时任务 -> [查询-用户优惠券是否已经过期][超时时间=%s毫秒]" , delay));
                    taskService.addTask(new CouponUserExpiredTask(couponUser, delay));
                }
            }
            log.info(String.format("租户[%s] -> 系统定时任务 -> [结束检查-用户优惠券是否已经过期][检查结果={数量%s}]",tenantId , couponList.size()));

            TenantContextHolder.removeLocalTenantId();
        }
    }
}
